<?php

/**
 * 日志处理类.
 */
namespace Lib\Core;

class Log extends \Home {

    /**
     * 日志目录.
     *
     * @var string
     */
    protected $logDir;

    /**
     * 打开的文件资源.
     *
     * @var array
     */
    protected $openFiles = array();

    /**
     * 消息合子.
     *
     * @var array
     */
    protected $box = array();

    protected $config;

    /**
     * 构造方法，初始化日志目录的位置.
     *
     * return void
     */
    public function __construct() {
        $configClassName = \Main::$appNamespace . 'Config\Log';
        $this->config = $configClassName::instance();
        $this->logDir = $this->config->logDir;
        $this->logDir = rtrim($this->logDir, '/') . '/';
    }

    /**
     * 写日志.
     *
     * @param string $dir 目录.
     * @param string $content 类容.
     *
     * return void
     */
    public function write($dir, $content, $lock = false) {

        $dir = rtrim($this->logDir, '/') . '/' . $dir . '/';
        \Lib\Util\Comm::rMkdir($dir);
        $fileName = date('Y-m-d') . '.log';
        $file = $dir . '/' . $fileName;
        $content = date('Y-m-d H:i:s') . ' ' . $content . PHP_EOL;
        $fp = $this->fopen($file, $lock);
        if ($lock) {
            flock($fp , LOCK_EX);
            fwrite($fp, $content);
            flock($fp , LOCK_UN);
        } else {
            fwrite($fp, $content);
        }
    }

    /**
     * 运行记录开始.
     *
     * @param string $class 类名称.
     * @param string $func  方法名称.
     * @param string $msg   信息.
     *
     * @return string 唯一的KEY
     */
    public function start($class, $func, $msg = '') {
        if (!$this->isOpen()) {
            return;
        }
        $key = uniqid('', true);
        //$msg = $this->toString($msg);
        if ($msg || is_array($msg)) {
            $msg = json_encode($msg);
        }
        $string = $class . '::' . $func . '@' . $msg;
        $this->box[$key][0] = $string;
        $this->box[$key][1] = microtime(true);
        return $key;
    }

    /**
     * 运行结束.
     *
     * @param string $key 开始方法返回的key.
     *
     * @return void
     */
    public function end($key) {
        if (!$this->isOpen()) {
            return;
        }
        if (!isset($this->box[$key])) {
            return;
        }
        $start = $this->box[$key][1];
        $end = microtime(true);
        $msg = $this->box[$key][0] . '@start:' . $start . '@use:' . round(($end - $start), 4);
        unset($this->box[$key]);
        $this->write('run', $msg);
    }

    private function fopen($file, $reOpen = false) {
        if ($reOpen) {
            return $this->openFiles[$file] = fopen($file, 'a');
        }
        if (empty($this->openFiles[$file])) {
            $this->openFiles[$file] = fopen($file, 'a');
        }
        return $this->openFiles[$file];
    }

    private function isOpen() {
        return $this->config->open;
    }

    private function toString($msg) {
        if (!$msg) {
            return '';
        }
        if (!is_array($msg) && !is_object($msg)) {
            return $msg;
        }
        $key = '';
        foreach ($msg as $key => $val) {
            if (!is_array($val) && !is_object($val)) {
                $str = $val;
            } else {
                $str = $this->toString($val);
            }
            $key .= 'Key:@' . $key . '@, Value:@' . $str . '@';
        }
        return $key;
    }

    public function __destruct() {
        foreach ($this->openFiles as $fp) {
            fclose($fp);
        }
    }

}